In [1]:
# On the top cell run:
from IPython.core.display import display, HTML
from IPython.core.magic import register_cell_magic
@register_cell_magic
def toggle_code(self, cell):
    display(HTML('''
        <script>code_show=true;
        function code_toggle() {
            if (code_show) { $('div.input').hide();}
            else {$('div.input').show();}
            code_show = !code_show
        }
        $(document).ready(code_toggle);
        </script>
        <button onClick="javascript:code_toggle()">Mostrar código</button>'''
    ))
    return display(HTML('<p></p>'))
In [2]:
%%toggle_code
# This comment is necessary for the magic to work

Lima Buendía

0.Preparación de ambiente y lectura de datos

In [81]:
#Carga de librerías
import boto3
import io
import dotenv
from dotenv import load_dotenv
import os
from dotenv import dotenv_values
import OpenBlender 
import pandas as pd
import re

from io import StringIO
import json
import numpy as np

from datetime import datetime, timedelta
import seaborn as sns
import matplotlib.pyplot as plt
import matplotlib.dates as mdates
from nltk.corpus import stopwords

import nltk
nltk.download('stopwords')

from wordcloud import WordCloud, STOPWORDS

import plotly.express as px
import plotly.graph_objects as go
import plotly.io as pio
from ipywidgets import widgets
import ipywidgets as widgets
from IPython import display
import plotly.figure_factory as ff
from IPython.display import Image, display
[nltk_data] Downloading package stopwords to
[nltk_data]     C:\Users\Elizabeth\AppData\Roaming\nltk_data...
[nltk_data]   Package stopwords is already up-to-date!
In [5]:
# convertimos a minúsculas
def limpiar(texto):
    nuevo_texto = texto.lower()
# Eliminación de espacios en blanco múltiples
    nuevo_texto = re.sub("\\s+", ' ', nuevo_texto)
# Eliminación de signos de puntuación
    regex = '[\\!\\"\\#\\$\\%\\&\\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^_\\`\\{\\|\\}\\~]'
    nuevo_texto = re.sub(regex , ' ', nuevo_texto) 
# Eliminación de números
    nuevo_texto = re.sub("\d+", ' ', nuevo_texto)
    return(nuevo_texto)
In [6]:
# convertimos a minúsculas
def limpiar_tokenizar(texto):
    nuevo_texto = texto.lower()
# Eliminación de espacios en blanco múltiples
    nuevo_texto = re.sub("\\s+", ' ', nuevo_texto)
# Eliminación de signos de puntuación
    regex = '[\\!\\"\\#\\$\\%\\&\\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^_\\`\\{\\|\\}\\~]'
    nuevo_texto = re.sub(regex , ' ', nuevo_texto) 
# Eliminación de números
    nuevo_texto = re.sub("\d+", ' ', nuevo_texto)
# Tokenización por palabras individuales
    nuevo_texto = nuevo_texto.split(sep = ' ')

# Eliminación de tokens con una longitud < 2
    nuevo_texto = [token for token in nuevo_texto if len(token) > 2]
    return(nuevo_texto)
In [7]:
def limpiar_tokenizar1(texto):
    nuevo_texto = texto.lower()
# Eliminación de espacios en blanco múltiples
    nuevo_texto = re.sub("\\s+", ' ', nuevo_texto)
# Eliminación de signos de puntuación
    regex = '[\\!\\"\\#\\{\'+}\\$\\%\\&\\\'\\(\\)\\*\\+\\,\\-\\.\\/\\:\\;\\<\\=\\>\\?\\@\\[\\\\\\]\\^_\\`\\{\\|\\}\\~\\\\´\\\\”]'
    nuevo_texto = re.sub(regex , ' ', nuevo_texto)
    nuevo_texto = nuevo_texto.strip()
# Eliminación de números
    #nuevo_texto = re.sub("\d+", ' ', nuevo_texto)
    return(nuevo_texto)
In [8]:
def tokenizar0(texto):
    # Tokenización por palabras individuales
    nuevo_texto = texto.split(sep = ' ')
    
    nuevo_texto = [token for token in nuevo_texto if not token in stop_words]
    



# Eliminación de tokens con una longitud < 2
    nuevo_texto = [token for token in nuevo_texto if len(token) > 2]
    nuevo_texto = (" ").join(nuevo_texto)
    return(nuevo_texto)
In [9]:
stop_words0 = list(stopwords.words('spanish'))
In [10]:
# Se añade la stoprword: 
stop_words=stop_words0
stop_words0.extend(("feminicidio", "feminista", "mexico","méxico", "tema", "feminicidios", "mujeres", "mujer", "violencia", "feminicida", "co", "si",  "tras", "años","https", "t"))

Lectura de datos

Los datos del proyecto están disponibles en S3.

In [ ]:
# Obtener el ambiente
load_dotenv()
In [ ]:
aws_access_key_id = os.getenv("aws_access_key_id")
aws_secret_access_key = os.getenv("aws_secret_access_key")
In [ ]:
# Preparacion de conexiones 
client = boto3.client('s3',
    aws_access_key_id = aws_access_key_id,
    aws_secret_access_key = aws_secret_access_key,
    region_name = 'us-east-1'
)
    
# Creating the high level object oriented interface
resource = boto3.resource('s3',
    aws_access_key_id = aws_access_key_id,
    aws_secret_access_key = aws_secret_access_key,
    region_name = 'us-east-1'
)

session = boto3.Session(aws_access_key_id=aws_access_key_id,
                        aws_secret_access_key=aws_secret_access_key
)
In [ ]:
# parámetros
s3_res = session.resource('s3')
csv_buffer = StringIO()
bucket_name = 'lima-buendia'

m1 = 'processed/cleaned_metacloud.csv'
m2 = 'processed/cleaned_metacloud_oct_nov.csv'
m3 = 'processed/cleaned_twitter.csv'
m4 = 'processed/cleaned_fp.csv'
m5 = 'processed/cleaned_fg.csv'
m6 = 'processed/agregados_nacionales.csv'
m7 = 'processed/defunciones_inegi.csv'
m8 = 'processed/tweets_pos_neg.csv'
m9 = 'processed/femi_virales.csv'
m10 = 'processed/Analisis_palabras_groups.csv'
m11 = 'processed/freq_anual20v1.csv'
m12 = 'processed/graf.csv'
m13 = 'processed/tabla1.csv'
m14 = 'processed/tabla.csv'
m15 = 'processed/otras_pag.csv'
m16 = 'processed/clasificacion_medios.csv'
m17 = 'processed/graf_deb.csv'
m18 = 'processed/graf_ingrid.csv'
m19 = 'processed/tabla3.csv'
m20 = 'processed/graf_deb_pages.csv'
In [ ]:
objm1 = client.get_object(Bucket = bucket_name, Key = m1)
objm2 = client.get_object(Bucket = bucket_name, Key = m2)
objm3 = client.get_object(Bucket = bucket_name, Key = m3)
objm4 = client.get_object(Bucket = bucket_name, Key = m4)
objm5 = client.get_object(Bucket = bucket_name, Key = m5)
objm6 = client.get_object(Bucket = bucket_name, Key = m6)
objm7 = client.get_object(Bucket = bucket_name, Key = m7)
objm8 = client.get_object(Bucket = bucket_name, Key = m8)
objm9 = client.get_object(Bucket = bucket_name, Key = m9)
objm10 = client.get_object(Bucket = bucket_name, Key = m10)
objm11 = client.get_object(Bucket = bucket_name, Key = m11)
objm12 = client.get_object(Bucket = bucket_name, Key = m12)
objm13 = client.get_object(Bucket = bucket_name, Key = m13)
objm14 = client.get_object(Bucket = bucket_name, Key = m14)
objm15 = client.get_object(Bucket = bucket_name, Key = m15)
objm16 = client.get_object(Bucket = bucket_name, Key = m16)
objm17 = client.get_object(Bucket = bucket_name, Key = m17)
objm18 = client.get_object(Bucket = bucket_name, Key = m18)
objm19 = client.get_object(Bucket = bucket_name, Key = m19)
objm20 = client.get_object(Bucket = bucket_name, Key = m20)
In [11]:
# mediacloud
df=pd.read_csv(objm1['Body'])

df_oct_nov=pd.read_csv(objm2['Body'])

#twitter
df2=pd.read_csv(objm3['Body'])

#facebook pages
fp = pd.read_csv(objm4['Body'])

#Facebook groups
fg=pd.read_csv(objm5['Body'])

#delitos agregados
d_agregados=pd.read_csv(objm6['Body'])

#defunciones INEGI
defunciones_inegi = pd.read_csv(objm7['Body'])

# Tweets positivos y negativos
tw = pd.read_csv(objm8['Body'])

# Feminicidios más virales
fem_virales = pd.read_csv(objm9['Body'])

# Gráfica (Facebook Groups)
graf = pd.read_csv(objm10['Body'])

# Treemap 
graf_1 = pd.read_csv(objm11['Body'])

# Gráfica (Facebook Pages) 
graf_2 = pd.read_csv(objm12['Body'])

# Tabla 1 
tabla1 = pd.read_csv(objm13['Body'])

# Tabla 2
tabla2 = pd.read_csv(objm14['Body'])

# Otras páginas
otras_pag = pd.read_csv(objm15['Body'])

# Clasificación de medios

clasificacion = pd.read_csv(objm16['Body'])

# Debanhi Escobar
graf_deb = pd.read_csv(objm17['Body'])

# Ingrid Escamilla
graf_ingrid = pd.read_csv(objm18['Body'])

# Debanhi Escobar (Facebook Pages)
tabla3 = pd.read_csv(objm19['Body'])

graf_deb_pages = pd.read_csv(objm20['Body'])
C:\Users\Elizabeth\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py:3058: DtypeWarning: Columns (5,18) have mixed types.Specify dtype option on import or set low_memory=False.
  interactivity=interactivity, compiler=compiler, result=result)
C:\Users\Elizabeth\Anaconda3\lib\site-packages\IPython\core\interactiveshell.py:3058: DtypeWarning: Columns (38,39,40) have mixed types.Specify dtype option on import or set low_memory=False.
  interactivity=interactivity, compiler=compiler, result=result)
In [12]:
delitos_excluir = ['Rapto', 'Secuestro', 'Corrupción de menores', 'Extorsión', 'Lesiones', 'Otros delitos contra la sociedad', 'Tráfico de menores']
d_agregados=d_agregados[~d_agregados['Tipo de delito'].isin(delitos_excluir)]

1. Intoducción y contexto

México vive un problema generalizado de violencia contra las mujeres, más de la mitad de país cuenta con alerta de género, un conjunto de acciones gubernamentales de emergencia para enfrentar y erradicar la violencia feminicida en un territorio determinado. Ante esta situación, se buscó analizar lo que se comenta y la cobertura mediática de los feminicidios en México utilizando distintas fuentes de información en el lapso de enero de 2017 a junio de 2022.

A partir de ahí, se puso especial énfasis en casos que fueron mediáticamente populares. Los insumos de este análisis fueron publicaciones en Facebook de grupos y páginas públicas, utilizando la herramienta Crowdtangle; igualmente, se obtuvieron post de Twitter utilizando la API para buscar tweets que respondieran a la búsqueda feminicidio en México; y en medios se buscó de la misma manera utilizando MediaCloud.

Por último, también se integraron datos abiertos sobre carpetas de investigación que hubieran sido catalogadas como feminicidios, así como homicidios dolosos de mujeres del Secretariado Ejecutivo del Sistema Nacional de Seguridad Pública. Igualmente del Instituto Nacional de Estadística y Geografía (INEGI), se obtuvieron los datos sobre las muertes de mujeres en manos de un familiar, esto como una variable proxi de feminicidios.

Así que, en conjunto entre el Centro ITAM para Datos + Algoritmos + Sociedad y SocialTIC, la información a analizar es de las siguientes fuentes:

  • MediaCloud
  • Facebook Pages
  • Facebook Groups
  • Twitter
  • Secretariado Ejecutivo del Sistema Nacional de Seguridad Pública
  • INEGI (defunciones)

Adicional a las fuentes de información menciondas, SocialTIC compartió una base de datos con los nombres de víctimas que se consideran como los más mediáticos. Parte de esta información fue obtenida del sitio #nosvanaverjuntas del Observatorio Ciudadano Nacional de Feminicidio.

In [13]:
fem_virales_ag = fem_virales.groupby('YM').agg({'Caso': lambda x: x.tolist()}).reset_index()
In [14]:
fem_virales_ag['# de Casos'] = fem_virales_ag['Caso'].map(len)
In [15]:
colorscale = [[0, '#4d004c'],[.5, '#f2e5ff'],[1, '#ffffff']]
table1 = ff.create_table(fem_virales_ag, colorscale=colorscale)
for i in range(len(table1.layout.annotations)):
    table1.layout.annotations[i].font.size = 9

table1.show()

2. Objetivo y preguntas de análisis

El proyecto tiene como objetivo poder identificar qué variables influyen para que un feminicidio se vuelva viral. Bajo este contexto, algunas de las preguntas que, de manera inicial, se pretenden contestar son:

  • ¿Qué es viralidad?
  • ¿Qué feminicidios se mencionan en las redes sociales?
  • ¿Se habla durante meses de un mismo caso de feminicidio?
  • ¿Los medios locales y nacionales hablan de los mismos casos?

3. Análisis Exploratorio de los datos

En la primera sección, Introducción y contexto, se mencionan diferentes fuentes de datos que hacen referencia a redes sociales (facebook pages, facebook groups y twitter), encabezados de noticias e información estadística de feminicidios. Por lo que, en esta sección se presentan los hallazgos principales de cada una de las fuentes, así como las series temporales con el objetivo de entender si se tiene el mismo comportamiento entre ellas y cómo ha evolucionado el tema del feminicidio.

Las fuentes de información que se consideraron son:

  • MediaCloud. Es una plataforma open source para el análisis de medios. Entre las variables que se tienen en los datos está la fecha de publicación, el encabezado de la noticia y el medio que lo está publicando. Este último puede ser local o nacional, por ejemplo: "El Sol de Morelos" y "El Universal", respectivamente.
  • Facebook Pages. Es una página creada con el obejtivo de ser un canal de comunicación dentro de la red social. Se considera la fecha del post, el nombre de la página, el mensaje publicado y la interacción. La interacción está definida como cualquier acción que realiza el usuario con la publicación sin distinguir si es positiva o negativa.
  • Facebook groups. Es un espacio dentro de Facebook, en el cual distintos usuarios de facegook pueden compartir información o conocimiento. Al igual que en las páginas, se tienen las variables de fecha de publicación del mensaje, los mensajes y las interacciones.
  • Twitter. Es un servicio de microblogueo, es decir, permite a sus usuarios enviar y publicar mensajes breves de menos de 180 caracteres. El conjunto de datos está conformado por los tweets y las variables a analizar son: fecha de publicación y tweet.
  • Tweets. Base de datos publicada por el INEGI con información de tweets positivos y negativos sin distinguir por tema.
  • Secretariado Ejecutivo del Sistema Nacional de Seguridad Pública. El conjunto de datos está conformado por estadísticas mensuales por estado de diversos tipos de delito (Homicidio, feminicidios, abortos, lesiones). La variable que resulta de interés es tipo de delito, a partir de la cual se exlcuyen los siguentes delitos: rapto, secuestro, corrupción de menores, extorsión, lesiones, otros delitos contra la sociedad y tráfico de menores.
  • Defunciones del INEGI. Para la conformación del conjunto de datos se utilizó la variable presunto, filtrando por homicidios de mujeres.

A manera de resumen, adicional a las fechas de publicación o mes de registro de la información, las variables a analizar por fuente son:

Fuente Observaciones Columnas Variable
MediaCloud 145,174 19 encabezado
Facebook pages 335,653 51 Mensaje, nombre de la página e interacciones
Facebook groups 56,124 11 Mensaje e interacciones
Twitter 149,465 16 Tweet
Tweets INEGI 79 11 Total de tweets
Secretariado 58,880 21 Tipo de delito
Defunciones 48 11 Presunto / Homicidio de mujeres
In [16]:
fg.rename(columns={'year':'Year', 'month':'Month', 'clean_message':'Clean_message_FBgroups', 'Total Interactions':'Total_Interactions_FBgroups'}, inplace=True)
In [17]:
fp.rename(columns={'year':'Year', 'month':'Month', 'clean_message':'Clean_message_FBpages', 'Total Interactions':'Total_Interactions_FBpages'}, inplace=True)
In [18]:
d = pd.DataFrame(df.groupby(['YM', 'year','month']).agg({'title':lambda x: x.dropna().size}).rename(columns={'title':'Title_MC'})).reset_index()
d_comp = df_oct_nov.groupby(['YM', 'year','month']).agg({'feminicidio*-count':sum}).rename(columns={'feminicidio*-count':'Title_MC'}).reset_index()
d = pd.concat([d, d_comp])
d = d.groupby(['YM', 'year', 'month']).agg({'Title_MC': lambda x: x.sum()}).reset_index()
d=d.sort_values(by=['year', 'month'])
dfp = pd.DataFrame(fp.groupby(['YM', 'Year','Month']).agg({'Clean_message_FBpages':lambda x: x.dropna().size}).rename(columns={'Clean_message_FBpages':'messages_FBP'})).reset_index()
dfg = pd.DataFrame(fg.groupby(['YM', 'Year','Month']).agg({'Clean_message_FBgroups':lambda x: x.dropna().size}).rename(columns={'Clean_message_FBgroups':'messages_FBG'})).reset_index()
dtw = pd.DataFrame(df2.groupby(['YM', 'year','month']).agg({'text':lambda x: x.dropna().size}).rename(columns={'text':'tweets'})).reset_index()
dfpi = pd.DataFrame(fp.groupby(['YM', 'Year','Month']).agg({'Total_Interactions_FBpages':lambda x: x.sum()}).rename(columns={'Total_Interactions_FBpages':'Facebook Pages'})).reset_index()
dfgi = pd.DataFrame(fg.groupby(['YM', 'Year','Month']).agg({'Total_Interactions_FBgroups':lambda x: x.sum()}).rename(columns={'Total_Interactions_FBgroups':'Facebook Groups'})).reset_index()
d_agregados2 = d_agregados.groupby(['YM']).agg({'delitos':lambda x: x.dropna().sum()}).reset_index()
In [19]:
from IPython.core.display import HTML as Center

Center(""" <style>
.output_png {
    display: table-cell;
    text-align: center;
    vertical-align: middle;
}
</style> """)
Out[19]:

- Encabezados de MediaCloud

In [20]:
plt.figure(figsize = (16,7))
sns.set_style('darkgrid')
sns.barplot(x = 'month',
            y = 'Title_MC',
            hue = 'year',
            data = d,
            palette = "rocket_r")
plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left', borderaxespad=0, frameon=False, fontsize=12)
plt.xlabel('Mes', fontsize=12)
plt.ylabel('Encabezados', fontsize=12)
plt.title("Encabezados de noticias por mes y año", fontsize = 15)
plt.tick_params(labelsize=12)
plt.show()
  • Al diferenciar por mes y año, se observan tres picos: febrero 2020, noviembre 2020 y marzo 2021.

  • 2020 fue un año en donde hubo el mayor volumen de encabezados; en comparación con este, 2021 presenta niveles menores, pero crecientes y mucho mayores a la cantidad de encabezados de los años anteriores.

  • Algo que resulta curioso es que, en 2020, se observan niveles altos en el último cuatrimestre, mientras que en 2021 esto ocurre en el primer semestre.

In [21]:
plt.figure(figsize = (16,7))
ax = sns.lineplot(x="YM", y="Title_MC", marker='o', linestyle='-', markersize=8, data=d)
ax.set_ylabel('Encabezados', fontsize=12);
ax.set_xlabel('Año', fontsize=12);
ax.set_xticks([1, 13, 25, 37, 49, 60])
ax.set_xticklabels(['2017-01', '2018-01', '2019-01', '2020-01', '2021-01', '2021-12'], fontsize=12)



_=ax.set_title('Serie de tiempo encabezados de noticias, 2017 a 2022', fontsize=15)

Al analizar la serie de tiempo de los encabezados, se observa que van a la alza y a partir de junio 2020 no regresan a los mismos niveles que en 2019.

- Facebook pages y groups

Como se menciona al inicio de la sección, las variables que se analizan de estas fuentes son: mensajes e interacciones. En ambos casos, se considera tanto la información agregada anual como por mes y año.

In [22]:
dfbk = pd.merge(dfg, dfp, how='left')
dfbk.rename(columns = {'messages_FBG':'Facebook groups', 'messages_FBP':'Facebook pages'}, inplace = True)
df_melt = pd.melt(dfbk, id_vars=['YM'], value_vars=['Facebook groups', 'Facebook pages'])
df_melt3 = pd.melt(dfbk, id_vars=['Year'], value_vars=['Facebook groups', 'Facebook pages'])
Mensajes: agregados anuales
In [23]:
g1=sns.catplot(data=df_melt3, x="Year", y="value", hue="variable", kind="bar", palette="Set2", aspect=3, linewidth = 0.2)
plt.xticks(rotation=90)

g1._legend.remove()
plt.xticks(rotation=90)
plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left', borderaxespad=0, frameon=False)
plt.xlabel('Año')
plt.ylabel('# Mensajes')
_=plt.title("Mensajes en facebook (groups VS pages) por año, 2017 a 2022") 
  • El volumen de mensajes en Facebook Groups presenta una tenencia positiva hasta 2020; despúes de este año muestra una caída y después vuelve a crecer. Por el contrario, Facebook pages mantiene una tenedencia positiva para todos los años. Esto es diferente a lo que uno esperaría, pues al ser la misma fuente se pensaría que tienen el mismo comportamiento.

  • La información del año 2022 es parcial dado que la muestra considera la información hasta mayo. No obstante esto, se puede observar que la totalidad de mensajes en Facebook groups en todo el año 2019 es menor a lo que se ha registrado en tan solo 5 meses del 2022.

Mensajes: Agregados por mes y año
In [24]:
fig = px.bar(df_melt, x='YM', y='value', title='Mensajes en Facebook (groups VS pages), 2017 a 2022', color='variable', 
             color_discrete_sequence=['#9370DB','#CD96CD'], labels={'YM':'Mes-Año', 'value':'# Mensajes'})
fig.show()
  • Se puede considerar que, a partir de Febrero 2020 se tiene un antes y después en los mensajes de feminicidios; en este mes se observa un pico en ambas fuentes y ese valor no se ha vuelto a presentar.

  • Se puede notar un aumento de mensajes a partir de este mes (Febrero 2020) con un nivel promedio que ya no se reduciría a niveles anteriores a Febrero 2020.

  • A partir de Octubre 2020, se percibe un nivel constante de mensajes girando alrededor de post relacionados. Otro dato a notar es que los picos más grandes se presentan en los primeros semestres de cada año, considerando los ultimos 3 años: Febrero 2020, Abril 2021 y Mayo 2022.

  • Facebook Groups Y Facebook Pages no son centinelas; como se observa en la gráfica de datos anuales, el primero disminuye y en el último año muestra una ligera recuperación mientras que el último mantiene una tendencia creciente.

Interacciones: agregados anuales
In [25]:
interacciones = pd.merge(dfgi, dfpi, how='left')
df_melt0 = pd.melt(interacciones, id_vars=['Year'], value_vars=['Facebook Groups', 'Facebook Pages'])
df_melt2 = pd.melt(interacciones, id_vars=['YM'], value_vars=['Facebook Groups', 'Facebook Pages'])
In [26]:
f=sns.catplot(data=df_melt0, x="Year", y="value", hue="variable", kind="bar", palette="Set2", aspect=3, linewidth = 0.2)
plt.xticks(rotation=90)
f._legend.remove()
plt.xticks(rotation=90)
plt.legend(bbox_to_anchor=(1.02, 1), loc='upper left', borderaxespad=0, frameon=False)
plt.xlabel('Año')
plt.ylabel('Mensajes')
_=plt.title("Interacciones en facebook groups y pages por año, 2017 a 2022") 
Interacciones: agregados por mes y año
In [27]:
fig = px.bar(df_melt2, x='YM', y='value', title='Interacciones en facebook groups y pages, 2017 a 2022', color='variable', 
             color_discrete_sequence=['#9370DB','#CD96CD'], labels={'YM':'Mes-Año', 'value':'# Interacciones'})
fig.show()
  • Al igual que con los mensajes, hay un antes y un después en cuanto a interacciones de los feminicidios en Facebook Groups y Facebook Pages que ocurre en Febrero 2020.

  • De igual manera que con los mensajes, podemos notar un aumento de interacciones a partir de este mes (Febrero 2020) con un nivel promedio que ya no se reduciría a niveles anteriores a Febrero 2020.

  • A partir de Octubre 2020, se puede percibir, hasta cierto punto, ya que si existen picos, un nivel contanstante de interacciones girando alrededor de post relacionados. Otro dato a notar tambien es que los picos mas grandes se presentan en los primeros semestres de cada año, al igual que en mensajes, considerando los ultimos 3 años: Febrero 2022, Abril 2021 y Mayo 2022

  • En cuanto a Facebook Groups, podemos notar cómo a partir de Marzo de 2021, hay un declive en interacciones, comportamiento similar en los mensajes.

A partir de las gráficas anteriores, se puede concluir que:

  • a pesar de que ambas provengan de Facebook, los mensajes en Pages y Groups no tienen el mismo comportamiento.
  • las interacciones y los mensajes tienen un comportamiento similar sin importar la fuente.
In [28]:
fem_virales_ag['Caso'] = fem_virales_ag['Caso'].astype('str')
In [29]:
fem_virales_ag['Caso'] = fem_virales_ag['Caso'].str.replace('[', '')
fem_virales_ag['Caso'] = fem_virales_ag['Caso'].str.replace(']', '')
fem_virales_ag['Caso'] = fem_virales_ag['Caso'].str.replace("'", '')
In [30]:
totales = pd.merge(dfg, dfp[['YM', 'messages_FBP']],on='YM',how='left')
totales = pd.merge(totales, dtw[['YM','tweets']], on='YM', how='left')
totales= pd.merge(totales, d[['YM','Title_MC']], on='YM', how='left')
totales = pd.merge(totales, d_agregados2[['YM', 'delitos']], how='left')
totales = pd.merge(totales, defunciones_inegi, on='YM', how='left')
totales = pd.merge(totales, tw, on='YM', how='left')
#totales = pd.merge(totales, fem_virales_ag, on='YM', how='left')
totales = totales.set_index(['YM', 'Year', 'Month'])
In [31]:
# Obtenemos las deltas
totales1= totales - totales.shift(1)
In [32]:
# Estandarizamos los datos
totales3 = (totales - totales.mean()) / totales.std()
In [33]:
totales = totales.reset_index(level=['Year', 'Month'])
totales1 = totales1.reset_index(level=['Year', 'Month'])
totales3 = totales3.reset_index(level=['Year', 'Month'])
Uniendo todas las fuentes de información
In [34]:
totales3 = totales3.reset_index()
In [35]:
totales_a = totales.reset_index()
In [36]:
totales3.rename(columns = {'messages_FBG':'Mensajes Facebook Groups', 'messages_FBP':'Mensajes Facebook Pages', 
                          'Title_MC': 'Encabezados MediaCloud', '# de defunciones':'Defunciones INEGI', 'delitos': 'Delitos Secretariado', 
                          'Total_tweets': 'Total Tweets'}, inplace = True)
In [37]:
totales4 = pd.melt(totales3, id_vars =['YM', 'Year'], value_vars =['Mensajes Facebook Groups',
       'Mensajes Facebook Pages', 'tweets', 'Encabezados MediaCloud',
       'Delitos Secretariado', 'Defunciones INEGI', 'Total Tweets'])
In [38]:
fig = go.Figure()

fig = px.line(totales4, x="YM", y="value", color="variable",
              title='Datos estandarizados (Tweets, mensajes, encabezados, delitos y defunciones)',
             labels={"YM": "Periodo(Año-Mes)", "value": "Observaciones", "variable": "Fuente"})

fig.update_traces(
    line={"width": 1},
    marker={"size": 5},
    mode="lines+markers",
    hovertemplate = '%{x}: %{y:.2f}'
    
)

fig.update_layout(
    #dragmode="zoom",
    hovermode=None,
    yaxis_range=[-4, 10], 
    #legend=dict(traceorder="reversed"),
    height=700,
    width= 1000,
    template="none",
    margin=dict(
        t=100,
        b=100
    ),
    hoverlabel=dict(
        bgcolor="white",
        font_size=14,
        font_family="Rockwell"
    )
)


fig.update_layout(
    xaxis=dict(
        autorange=True,
        rangeselector=dict(
            buttons=list([
                dict(count=1,
                     label="1m",
                     step="month",
                     stepmode="backward"),
                dict(count=1,
                     label="YTD",
                     step="year",
                     stepmode="todate"),
                dict(count=1,
                     label="1y",
                     step="year",
                     stepmode="backward"),
                dict(step="all")
            ])
        ),
        rangeslider=dict(
            visible=True
        ),
        type="date"
    )
)

fig.add_bar(x=["2017-03", "2018-03", "2019-03", "2020-03", "2021-03", "2022-03"], y=[11, 11, 11, 11, 11, 11],
                base=[-4, -4, -4, -4, -4, -4],
                marker_color='rgba(250, 0, 242, 0.3)',
                name='8M',
                hovertemplate="%{x}",
                marker_line_width=0.2,
                marker_line_color='rgb(250, 0, 242)'
                )


fig.add_bar(x=["2017-11", "2018-11", "2019-11", "2020-11", "2021-11"], y=[11, 11, 11, 11, 11],
                base=[-4, -4, -4, -4, -4],
                marker_color='rgba(255, 115, 1, 0.83)',
                name='25N',
                hovertemplate="%{x}",
                marker_line_width=0.2,
                marker_line_color='rgb(255, 115, 1)'
                )

fig.add_bar(x=["2019-12", "2020-01", "2020-03", "2021-01", "2021-08", "2022-01"], y=[11, 11, 11, 11, 11, 11],
                base=[-4, -4, -4, -4, -4, -4],
                marker_color='rgba(232, 250, 0, 0.4)',
                name='COVID',
                hovertemplate="%{x}",
                marker_line_width=0.2,
                marker_line_color='rgb(232, 250, 0)'
                )

fig.add_bar(x=["2019-09", "2018-09"], y=[11, 11],
                base=[-4, -4],
                marker_color='rgba(18, 250, 0, 0.5)',
                name='MV',
                hovertemplate="%{x}",
                marker_line_width=0.2,
                marker_line_color='rgb(18, 250, 0)'
                )

fig.add_bar(x=["2022-02"], y=[11],
                base=[-4],
                marker_color='rgba(250, 0, 0, 0.6)',
                name='GU',
                hovertemplate="%{x}",
                marker_line_width=0.2,
                marker_line_color='rgb(250, 0, 0)'
                )

fig.add_bar(x=["2022-03", "2019-05", "2021-09", "2022-05"], y=[11, 11, 11, 11],
                base=[-4, -4, -4, -4],
                marker_color='rgba(13, 221, 218, 0.7)',
                name='Aborto',
                hovertemplate="%{x}",
                marker_line_width=0.2,
                marker_line_color='rgb(13, 221, 218)'            
                )


fig.add_annotation( # add a text callout with arrow
    text="Ingrid/Fátima", x="2020-02", y=7, arrowhead=1, showarrow=True
)

Para la conformación total del dataset, se eliminan los mensajes vacíos de Facebook Pages y Facebook Groups. Se valida que en la columna de encabezados no se tengan vacíos y en twitter también. Para una mejor visualización se estandarizan las series de tiempo.

En la gráfica anterior, se agregan ciertos hitos a nivel nacional y mundial para una mejor contextualización de la información, entre ellos:

Hito Descripción
8 de marzo (8M) Día interancional de la mujer
Aborto Legalización del aborto
Marea Verde (MV) Movimiento feminista a favor de la despenalización del aborto
(25N) Violencia contra la mujer
Covid Primeros casos registrados a nivel internacional y nacional

Adicional, se resalta el mes de Febrero 2020 que, como se menciona anteriormente, se podría considerar un punto de quiebre. En este mes ocurrieron los femnicidios de Ingrid y Fátima.

  • Cabe resaltar que la serie original de Twitter tiene 1 periodo faltante para Julio 2018 y presenta muchos meses con menos de 100 tweets. Se observan picos en algunos meses de 2018 y 2019.

  • Tanto la serie de Facebook Groups, Facebook Pages y MediaCloud presentan el pico más alto en Febrero 2020; Twitter para ese mismo periodo, presenta 247 tweets y presenta un pico similar al de las otras tres en diciembre (2 meses antes que el resto). Más adelante se pueden ver las nubes de palabras de estos dos meses.

    • Feb 2020
Fuente Palabras
MediaCloud Fátima, Ingrid, Ingrid Escamilla
Twitter País, gobierno, lópez obrador
 - Dic 2019

Fuente Palabras
MediaCloud Asesinada, género, presunta
Twitter Club América, américa sub, violador
  • Facebook Groups y Facebook Pages no presentan el mismo comportamiento. Por ejemplo, en marzo 2021 ambos presentan una alza considerabale en relación al mes anterior; en abril disminuyen y para los siguientes meses, la primera -Facebook Groups- presenta un comportamiento casi sin cambios y, Facebook Pages crece por tres meses consecutivos. Adicional a lo anterior, los últimos meses también tienen un comportamiento distinto. Facebook Groups tiene una tendencia a la alza con un crecimiento casi constante, mientras que Facebook Pages crece rápidamente y el último periodo presenta un cambio de pendiente.

  • Febrero, en distintos años, resulta ser un mes de picos:

    • series de Facebook y MediaCloud: en 2020
    • Twitter ocurre en 2018.
  • Otro punto que resulta de interés es la tendencia contraria que se observa entre MediaCloud y las de Facebook para el periodo de mayo 2020. El número de encabezados disminuye mientras que el total de páginas crece y el de grupos se mantiene casi estable.

En relación a los delitos reportados por el Secretariado,hay varios puntos que llaman la atención:

  • La serie de delitos presenta uno de sus picos más altos en Agosto 2018 y ninguna de las series de redes sociales ni encabezados presentan un pico cercano a ese periodo; en efecto, 3 de las 4 series presentan un movimento a la alza ligeramente grande, pero no llegan a ser los picos más grandes.
  • En el periodo en el que twitter presenta un pico (Diciembre 2019), los delitos presentan una disminución.
  • Noviembre 2019: facebook y MediaCloud van a la alza mientras que los delitos a la baja.
  • Febrero 2020: pico en varias series y los delitos en niveles similares a mayo 2019.
  • De junio a octubre de 2021, la serie de facebook groups hace una especie de parábola mientras que los delitos suben y bajan.

  • Marzo 2021 es uno de los puntos en donde las series, salvo twitter, coinciden.

En relación a las defunciones registradas por INEGI:

  • A finales de 2019 existió un incremento en las defunciones registradas por INEGI, tales defunciones se refieren a homicidios generados a mujeres. Mientras que en febrero de 2020 ocurrió una disminución, esto también sucedió con los datos de los tweets positivos y negativos.
  • Para los datos de tweets positivos y negativos, existió un crecimiento en marzo de 2020, sin embargo para ese periodo se puede notar que los mensajes de Facebook Pages disminuyeron.

NOTA: Para la construcción de los words clouds, se agregaron las palabras feminicidio, feminicidios, mujeres, mujer, violencia, feminicida, feminista, mexico, méxico tras, años,https a las stopping words.

In [39]:
# Filtrando la información para dic 19 y feb 20
df2019 = df[(df.YM=='2019-12')]
tw2019 = df2[(df2.YM=='2019-12')]

df2020 = df[(df.YM=='2020-02')]
fp2020 = fp[(fp.YM=='2020-02')]
fg2020 = fg[(fg.YM=='2020-02')]
tw2020 = df2[(df2.YM=='2020-02')]


df2019['title_limpio'] = df2019['title'].apply(lambda x: limpiar(x))
tw2019['title_limpio'] = tw2019['text'].apply(lambda x: limpiar(x))

df2020['title_limpio'] = df2020['title'].apply(lambda x: limpiar(x))
tw2020['title_limpio'] = tw2020['text'].apply(lambda x: limpiar(x))


text = df2020.title_limpio
text = ' '.join(text).lower()

texttw = tw2020.title_limpio
texttw = ' '.join(texttw).lower()

text19 = df2019.title_limpio
text19 = ' '.join(text19).lower()

texttw19 = tw2019.title_limpio
texttw19 = ' '.join(texttw19).lower()
In [40]:
wordcloud = WordCloud(width = 800, height = 800,
                background_color ='white',
                stopwords = stop_words0,
                colormap = 'tab10',
                collocations = True,
                min_font_size = 8).generate(text)
In [41]:
wordcloud_1 = WordCloud(width = 800, height = 800,
                background_color ='white',
                stopwords = stop_words0,
                colormap = 'tab10',
                collocations = True,
                min_font_size = 8).generate(texttw)
In [42]:
wordcloud19 = WordCloud(width = 800, height = 800,
                background_color ='white',
                stopwords = stop_words0,
                colormap = 'tab10',
                collocations = True,
                min_font_size = 8).generate(text19)
In [43]:
wordcloudtw19 = WordCloud(width = 800, height = 800,
                background_color ='white',
                stopwords = stop_words0,
                colormap = 'tab10',
                collocations = True,
                min_font_size = 8).generate(texttw19)
In [44]:
plt.figure(figsize = (14, 14), facecolor = None)
plt.subplot(2, 2, 1)
plt.imshow(wordcloud19)
plt.xticks([])
plt.yticks([])
_=plt.title('Encabezados Dic 2019')
#axarr[1].imshow(wordcloud_1)

plt.subplot(2, 2, 2)
plt.imshow(wordcloudtw19)
plt.xticks([])
plt.yticks([])
_=plt.title('Tweets Dic 2019')
In [45]:
plt.figure(figsize = (14, 14), facecolor = None)
plt.subplot(2, 2, 1)
plt.imshow(wordcloud)
plt.xticks([])
plt.yticks([])
_=plt.title('Encabezados Febrero 2020')
#axarr[1].imshow(wordcloud_1)

plt.subplot(2, 2, 2)
plt.imshow(wordcloud_1)
plt.xticks([])
plt.yticks([])
_=plt.title('Tweets Febrero 2020')

¿De qué están hablando los encabezados de las noticias y los Tweets en Diciembre 2019 y Febrero 2020?

  • Diciembre 2019 es el mes en el que se presenta el pico más alto para Twitter, mes en el que resaltan las palabras club américa, violador, feministas. En este mes, los jugadores se burlaron de un "violador en tu camino" un movimiento feminista iniciado en Chile. Por el contrario, ni los encabezados ni las fuentes de facebook muestran una frecuencia alta en relación a esto, salvo en la palabra violador y, aparece con mayor relevancia el nombre de una victima: Abril Pérez.
  • Febrero 2020 es el mes en el que concide el pico de Facebook groups, pages y MediaCloud coincide en Febrero 2020 y también con dos de los nombres de las víctimas de los feminicidos considerados como mediáticos: ingrid escamilla y fátima. Asimismo, se resalta la palabra de paro nacional. Por el contrario, en los tweets no se hace mención de un nombre de víctima en particular ni se hace mención del paro nacional.

4.¿Qué es viralidad?

Previo a la definición de viralidad se analizan las palabras frecuentes en cada fuente con el objetivo de identificar si existen algunas comunes entre ellas.

In [46]:
df_fuente = (
    graf_1.groupby(["fuente", "year"], as_index=False)
    .sum())

df_fuente["token"] = df_fuente["fuente"]
df_fuente["fuente"] = "año"


df_year = (
    graf_1.groupby(["year"], as_index=False).sum())
df_year['token']='año'
df_year['fuente']=''

df_total = df_fuente.append(
    graf_1[
        [
            "fuente",
            "year",
            "freq",
            "token"
            
        ]
    ]
)
df_total = df_total.append(
    df_year[
        [
            "fuente",
            "year",
            "freq",
            "token"
            
        ]
    ]
)
In [47]:
frame0 = None
frames = []
years= df_total['year'].unique()
for year in years:
    mask = df_total.year == year
    df_tmp = (df_total[mask])   
    treemap = go.Treemap(
        labels=df_tmp["token"], 
        values=df_tmp["freq"],
        parents=df_tmp["fuente"],
        branchvalues="total",
        pathbar_textfont_size=15,
        root_color="lightgrey",
        texttemplate='%{label} <br> %{value} <br> %{percentRoot}'
    )
    if frame0 is None:
        frame0 = treemap
    frames.append(go.Frame(name=f"frame-{year}", data=treemap
    ))
    
#Make sliders
sliders = [
    dict(
        steps=[
            dict(
                method="animate",
                args=[
                    [f"frame-{year}"],
                    dict(mode="e", frame=dict(redraw=True), transition=dict(duration=100))],
                label=f"{year}")
            for year in years
        ],
        transition=dict(duration=0),
        x=0,
        y=0,
        currentvalue=dict(
            font=dict(size=12), prefix="Año: ", visible=True, xanchor="center"
        ),
        len=1.0,
        active=1,
    )  
]

#create the layout object with slider parameters
layout = {
    "title": f"Top 10: Palabras por año de las fuentes consideradas (MediaCloud, Twitter, Facebook Pages y Facebook Groups)",
    "updatemenus": [
        { "type": "buttons",
            "buttons": [
                { "method": "animate",
                    "label": "play",
                    "args": [
                        None,
                        dict(
                            frame=dict(duration=700, redraw=True),
                            transition=dict(duration=100),
                            fromcurrent=True,
                            mode="immediate",
                        ),
                    ],
                }
            ],
        }
    ],
    "sliders": sliders,
}

#Create the final figure with layout and frames parameter
figure = go.Figure(
    data=frame0,
    layout=layout,
    frames=frames
)

colors=['#E6658E', '#C4C2AB', '#C9B5BC', '#A1C1C9', '#20667A']
figure.update_layout(margin = dict(t=25, l=25, r=25, b=25), treemapcolorway=colors)

figure.show()

A partir de los resultados anteriores, se decide explorar los casos de: (1) Ingrid Escamilla, uno de los dos feminicidios que corresponden al pico de febrero 2020; (2) Debahni Escobar por ser de los casos más recientes y (3) Lesvy por aparecer en varios periodos de la información de MediaCloud.

Con el objetivo de poder definir ¿qué es viralidad? se analiza lo siguiente:

  • En la información de MediaCloud, ¿se tienen diferencias en los medios locales y nacionales en alguno de los feminicidios? Es decir, los feminicidios antes mencionados aparecen tanto en medios nacionales como locales y el tema persiste por un periodo de tiempo prolongado?

  • ¿Cómo se puede definir un punto de refencia para la viralidad? Para esto, se consideraron las palabras "López Obrador" y dos casos dentro de los hitos: Debany e Ingrid.

  • En la información de facebook pages, ¿de qué otros temas se está hablando en las páginas que hablan de femincidios? ¿Cuál es la temporalidad de los mismos?

Para resolver estás dos últimas preguntas, se utilizó la librería fastText, que fue desarrollada por Facebook, la cual se puede utilizar para resolver varios problemas de Procesamiento de Lenguaje Natural. La función que utilizamos fue: train_unsupervised, cuyo parámetro es un archivo txt que contiene las oraciones, a partir de las cuales se hace el aprendizaje de los vectores de palabras.

Gracias a la implementación de esta función se pudieron encontrar las palabras similares a los nombres (nombre y apellido) de los feminicidios antes mencionados y así poder robustecer el análisis; es decir, antes del entrenamiento del modelo, por ejemplo, en el caso de Ingrid Escamilla Vargas se utilizaba el nombre completo. Con el resultado del modelo nos percatamos que también se tenía que incluir #Ingrid, #LeyIngrid, entre otros.

¿Se tiene la misma información a nivel nacional como local?
In [48]:
df['title_tokenizado'] = df['title'].apply(lambda x: limpiar_tokenizar1(x))
In [49]:
df['title_tokenizado'] = df['title_tokenizado'].apply(lambda x: tokenizar0(x))
In [50]:
clasificacion = clasificacion[['media_id', 'pub_country', 'about_country', 'Verificación']]
df_m1 = pd.merge(df, clasificacion, how="left", on=["media_id"])
In [51]:
hitos = df_m1[df_m1['title_tokenizado'].str.contains('gabriela bautista|alondra magali romero cortes|emma gabriela molina canto|lesvy berlín rivera osorio|valeria gutierres|jessica sevilla|victoria salas|mara fernanda castillo|mariana fuentes|anayetzin fragoso|dayana esmeralda|fanny morales garcia|rosalinda esthefanie morales garcía|emeli n.|vianca fernanda moreno labastida|yessica celene|evelyn rojas|arlet samantha|jimena paola|zyanya estefanía figueroa becerril|diana cristina ramírez martínez|maría del sol cruz jarquín|miranda mendoza flores|nancy noemí|seyni camila cobos medina|silvia ivanna mingo|olga gabriela kobel lara|fernanda paola ortiz jiménez|ana paola|guillermina berriolope|gabriela sánchez martínez|erika sánchez basaldua|judith abigail|maría eugenia guzmán galán|giselle garrido|alondra getsemani villaseñor|abril pérez|lesvy|diana celina gonzález hernández|nazaret b.|ingrid escamilla|fátima| fátima|fátima |fátima cecilia aldrighett|maria elena f.|nazaret bautista|mariam reyes|judith fernández cruz|sara sofía matus fernández|jessica gonzález villaseñor|alondra elizabeth gallegos garcía|elmy pachecho|carmen “caramelo”|lucero rubí ojeda huerta|xitlali elizabeth b.|nayeli guerrero herrera|bianca alejandrina l.|maricruz chiguil anota|fabiola ruiz lazcano|maría pilar|nicole|victoria salazar|wendy yoselin ricardo sevilla|ana lilia|maricela|montserrat bendimes roldán|karla romina|daniela toledo ocampo|nohemí medina y julizsa ramírez|michell pérez tadeo|atena|yolanda martínez|victoria guadalupe|maría fernanda contreras|debanhi escobar|sandra elizabeth pérez portillo|cecilia monzón|ximena monserrat martínez rangel|yrma lydya gamboa jiménez|brenda n')]
In [52]:
from sklearn.feature_extraction.text import CountVectorizer
word_vectorizer = CountVectorizer(ngram_range=(2,2), analyzer='word')
sparse_matrix = word_vectorizer.fit_transform(hitos['title_tokenizado'])
frequencies = sum(sparse_matrix).toarray()[0]




a = pd.DataFrame(frequencies, index=word_vectorizer.get_feature_names(), columns=['frequency'])
a= a.reset_index()



a = a.sort_values(['frequency'],ascending=False).head(20)
In [53]:
colorscale = [[0, '#4d004c'],[.5, '#f2e5ff'],[1, '#ffffff']]
table1 = ff.create_table(a, colorscale=colorscale)

for i in range(len(table1.layout.annotations)):
    table1.layout.annotations[i].font.size = 12
    table1.update_layout(title_text = 'Bigramas de los hitos más mediáticos', margin = {'t':50, 'b':100})
    

table1.show()
  • Al tomar bigramas, el feminicidio de Abril Pérez que ocurrió en noviembre del 2019 encabeza la lista. Este feminicidio dio pie a la Ley Abril. Seguido de éste, se tienen el de Ingrid Escamilla en el año 2020, el de Victoria Salazar. En quinto lugar se observa el caso Lesvy.
In [54]:
ingrid = ['ingrid escamilla', 'ingrid escamilla vargas']
lesvy = ['lesvy berlín rivera osorio', 'lesvy berlín', 'lesvy berlín rivera', 'lesvy']



df_m1["ingrid"] = df_m1['title_tokenizado'].apply(lambda x: 1 if any (i in x for i in  ingrid) else 0)
df_m1["lesvy"] = df_m1['title_tokenizado'].apply(lambda x: 1 if any (i in x for i in  lesvy) else 0)
In [55]:
# Analizando un par de casos...
ap = df_m1[df_m1['title_tokenizado'].str.contains('ingrid escamilla| ingrid escamilla | ingridescamilla')]
aa = ap.groupby(['title_tokenizado']).agg({'title_tokenizado':lambda x: x.dropna().size}).rename(columns={'title_tokenizado':'freq'}).reset_index().sort_values(['freq'],ascending=False).head(20)




ingrid1=df_m1.groupby(['YM', 'Verificación']).ingrid.agg('sum').reset_index()
ingrid1 = ingrid1[ingrid1['ingrid']>0]
pivot = pd.pivot_table(ingrid1, values = 'ingrid', index=['Verificación'], columns = 'YM').reset_index()
pivot=pivot.fillna(0)
pivot
Out[55]:
YM Verificación 2020-02 2020-03 2020-05 2020-11 2020-12 2021-02 2021-06 2021-07 2021-11
0 Local 113.0 2.0 0.0 0.0 17.0 16.0 4.0 0.0 1.0
1 NO - España 1.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
2 OK Nacional 116.0 1.0 1.0 1.0 5.0 6.0 3.0 3.0 0.0
  • Como se observa en la tabla anterior, las noticias locales y nacionales no necesariamente van de la mano. Por ejemplo, en los meses de Mayo y Noviembre 2020 a nivel nacional hay una noticia que habla de Ingrid, pero no a nivel local. Y llama la atención que a nivel local, en diciembre 2012 haya una frecuencia alta.
Punto de referencia de viralidad a partir de Facebook Groups
In [56]:
fig7 = px.line(graf, x='Month-Year', y='value',title='Distribución de las palabras analizadas a traves del tiempo', markers=True, color='variable', symbol='variable')
fig7.show()

¿Que podemos observar?

Los picos máximos que se observan para cada una de las series son:

  • 'amlo': casi 74,000 interacciones

  • 'ingrid': 15,400 interacciones

  • 'debanhi': 19,500 interacciones

En primera instancia, lo que llama la atención es la diferencia en el número de interacciones que se tienen entre una palabra de connotación política y otra relacionada con un feminicidio. Ambas muestran una caída en Febrero de 2020 (fecha ya antes mencionada) y en algunos casos como Julio 2020 y Marzo 2021, muestran picos en sus respectivas dimensiones.

Dejando de lado la inminente interactividad mostrada por la palabra amlo, se puede observar que tanto el caso de Ingrid como el de Debanhi muestran una caída muy pronunciada en interacciones tendiendo a cero después de dos meses. Sin embargo, el caso de Debanhi muestra, desde la fecha del feminicidio, más interacciones en comparación con el de Ingrid.

In [57]:
fig = px.density_heatmap(graf_ingrid, x="Group Name", y="words", z="Total de interacciones por mensaje", text_auto=True)
fig.update_layout(
    title_text='Top 10 de mensajes con mayor número de interacciones (Ingrid Escamilla Vargas)', 
    title_x=0.5, 
    width=1100, 
    height=1000,
    yaxis_autorange='reversed',
)

fig.update_xaxes(tickangle=90)

fig.show()
In [58]:
fig = px.density_heatmap(graf_deb, x="Group Name", y="words", z="Total de interacciones por mensaje", text_auto=True)
fig.update_layout(
    title_text='Top 10 de mensajes con mayor número de interacciones (Debanhi Escobar)', 
    title_x=0.5, 
    width=1100, 
    height=1000,
    yaxis_autorange='reversed',
)

fig.update_xaxes(tickangle=90)

fig.show()

Dentro del top 10 de mensajes con mayor número de interacciones, se obtuvieron los grupos asociados a estos mensajes. En el caso de Ingrid Escamilla se observa que el primer lugar lo ocupa un grupo de connotación política. En el de Debanhi Escobar solo se observa un grupo de connotación política en la posición número 6.

Facebook Pages

Idea: Obtener todas las palabras relacionadas con los casos antes mencionados y analizar en qué medios estaban hablando de ellas, así como saber qué otros temas surgían al mismo tiempo.

  • Ingrid Escamilla Vargas
  • En la siguiente tabla se muestran las 18 páginas relacionadas al top 10 de mensajes con mayor número de interacciones de febrero de 2020 que corresponden al hito de "Ingrid Escamilla Vargas". En dicha tabla se puede observar que un mismo mensaje que se comparte, tanto en la página En Un 2x3 Tamaulipas como en Museo Memoria y Tolerancia , cuenta con distinto número de interacciones.
In [59]:
tabla1['words'] = tabla1['words'].str.replace("[", '')
tabla1['words'] = tabla1['words'].str.replace("]", '')
tabla1['words'] = tabla1['words'].str.replace("'", '')
In [60]:
colorscale = [[0, '#4d004c'],[.5, '#f2e5ff'],[1, '#ffffff']]
table1 = ff.create_table(tabla1, colorscale=colorscale)
for i in range(len(table1.layout.annotations)):
    table1.layout.annotations[i].font.size = 9
    table1.update_layout(title_text = 'Top 10 de mensajes (Ingrid Escamilla Vargas) con mayor número de interacciones, Febrero 2020', margin = {'t':50, 'b':100})

table1.show()
In [61]:
tabla2['words'] = tabla2['words'].str.replace("[", '')
tabla2['words'] = tabla2['words'].str.replace("]", '')
tabla2['words'] = tabla2['words'].str.replace("'", '')
In [62]:
import textwrap

def customwrap(s, width=10):
    return "<br>".join(textwrap.wrap(s,width=width))
In [63]:
tabla2['words'] = tabla2.words.map(customwrap)
In [64]:
tabla2['Page Name'] = tabla2['Page Name'].map(customwrap)
  • El siguiente gráfico muestra cuáles fueron las páginas del top 10 de mensajes con mayor número de interacciones (Febrero 2020) que después de que ocurrió el feminicidio de Ingrid Escamilla siguieron hablando del tema, solo 7 de las 18. Por lo que, se puede observar que sólo El Universal Online , un mes después (Marzo 2020) cometó de dicho feminicidio.
In [65]:
fig = px.sunburst(tabla2, path=['YM', 'Page Name', 'words'], values='# Messages', color='Total de interacciones por mensaje',
                  color_continuous_scale='RdBu',
                  )

fig.update_layout(
    height=800,
    title_text='Historia del hito "Ingrid Escamilla Vargas'
)

fig.show()
  • Se realizó un gráfico interactivo que muestra de qué otros temas hablan estás páginas de Facebook del top 10 de mensajes (Ingrid Escamilla Vargas), para ello se consideró el top 20 de palabras. La página Museo Meoria y Tolerancia dentro del top 20 de palabras sale "Fátima", en Forbes "AMLO" y en Venga La Alegría "Debanhi".
  • Sin embargo, cabe mencionar que este gráfico se ve únicamente al correr dicho notebook, así que, en la siguiente gráfica se puede ver cómo es.
In [82]:
display(Image(filename='graf.png', embed=True))
In [66]:
button1 = widgets.Dropdown(
    options=list(graf_2['Page Name'].unique()),
    description='Page Name:',
)

trace = go.Figure(go.Bar(x = graf_2['clean_txt'], y = graf_2['count']
                      ))
trace.update_traces(marker_color='rgba(147, 48, 204, 0.32)',
                  marker_line_width=2, opacity=0.8)
trace.update_layout(
    title_text='Otros temas de los que hablan las páginas de Facebook del top 10 de mensajes (Ingrid Escamilla Vargas)'
)

g = go.FigureWidget(trace)
In [67]:
def validate():
    if button1.value in graf_2['Page Name'].unique():
        return True
    else:
        return False
In [68]:
def response(change):
    
    if validate():
            filter_list = [i for i in
                           zip(graf_2['Page Name'] == button1.value)]
            temp_df = graf_2[filter_list]

    else:
        filter_list = [i for i in
                           zip(graf_2['Page Name'] == button1.value)]
        temp_df = graf_2[filter_list]
    x = temp_df['clean_txt']
    y = temp_df['count']
        
        
    with g.batch_update():
        g.data[0].x = x
        g.data[0].y = y
        g.layout.barmode = 'overlay'
        g.layout.xaxis.title = 'Words'
        g.layout.yaxis.title = 'Count'


button1.observe(response, names="value")
In [69]:
container2 = widgets.HBox([button1])
widgets.VBox([container2, g])
In [70]:
otras_pag['words'] = otras_pag.words.map(customwrap)
In [71]:
otras_pag['Page Name'] = otras_pag['Page Name'].map(customwrap)
  • En el siguiente gráfico se presenta qué otras páginas estuvieron hablando del feminicidio de "Ingrid Escamilla Vargas" después de que ocurrió (Febrero 2020). Por lo que, se puede notar que sólo en 2 páginas se mencionó de dicho caso en 2020.
In [72]:
fig = px.sunburst(otras_pag, path=['YM', 'Page Name', 'words'], values='# Messages', color='Total de interacciones por mensaje',
                  color_continuous_scale='RdBu',
                  )

fig.update_layout(
    height=800,
    title_text='Otras páginas que siguieron hablando del tema del feminicidio de "Ingrid Escamilla Vargas"'
)

fig.show()
  • Debanhi Escobar
  • En la tabla siguiente se presenta el top 10 de mensajes con mayor número de interacciones que hablaron del feminicidio de "Debanhi Escobar" en abril de 2022. En comparación con el feminicidio de "Ingrid Escamilla", el número de interacciones fue menor. También, cabe señalar que existen mensajes que se compartieron en más de 1 página, por lo que en total son 40 páginas que forman este top 10 de mensajes.
In [73]:
tabla3['words'] = tabla3['words'].str.replace("[", '')
tabla3['words'] = tabla3['words'].str.replace("]", '')
tabla3['words'] = tabla3['words'].str.replace("'", '')
In [74]:
colorscale = [[0, '#4d004c'],[.5, '#f2e5ff'],[1, '#ffffff']]
table1 = ff.create_table(tabla3, colorscale=colorscale)
for i in range(len(table1.layout.annotations)):
    table1.layout.annotations[i].font.size = 9
    table1.update_layout(title_text = 'Top 10 de mensajes (Debanhi Escobar) con mayor número de interacciones, Abril 2022', margin = {'t':50, 'b':100})

table1.show()
  • En la siguiente gráfica se muestra si estás páginas siguieron hablando de dicho feminicidio después de que ocurrió y sí, 17 páginas lo siguieron mencionando de las 40.
In [75]:
graf_deb_pages['words'] = graf_deb_pages['words'].str.replace("[", '')
graf_deb_pages['words'] = graf_deb_pages['words'].str.replace("]", '')
graf_deb_pages['words'] = graf_deb_pages['words'].str.replace("'", '')
In [76]:
graf_deb_pages['words'] = graf_deb_pages.words.map(customwrap)
In [77]:
fig = px.sunburst(graf_deb_pages, path=['YM', 'Page Name', 'words'], values='# Messages', color='Total de interacciones por mensaje',
                  color_continuous_scale='RdBu',
                  )

fig.update_layout(
    height=800,
    title_text='Historia del hito "Debanhi Escobar"'
)

fig.show()
In [78]:
import plotly.offline
from plotly.offline import init_notebook_mode
plotly.offline.init_notebook_mode()

5.Conclusiones y futuros análisis

En esta primera etapa del proyecto se analizaron diversas fuentes de datos en el que se decidió no incluir la información de Twitter por tener tantos periodos con valores con menos de 100 tweets y, como se observa en la gráfica de comparación de fuentes (Top 10: Palabras por año de las fuentes consideradas (MediaCloud, Twitter, Facebook Pages y Facebook Groups), por el volumen de información pierde relevancia.

Se concluye también que la información de Facebook (páginas y grupos) no tienden a tener el mismo comportamiento. También se notó que si un mismo mensaje se comparte en dos páginas, no necesariamente tendrá el mismo impacto.

La información de mediaCloud se consideró un marco de referencia al tema y a partir de los datos de Facebook se entrenó un modelo no supervisado para la identificación de similitud de texto.

A partir de los hallazgos generados se podría considerar que el feminicidio de Ingrid Escamilla marca un antes y un después en el tema, sin embargo aún no se puede concluir qué hace que un feminicidio sea viral. Por ejemplo, en el caso de Lesvy ninguna de las series presenta un pico en el periodo donde ocurrió, pero en los datos de MediaCloud el tema de Lesvy se mantiene en varios meses.

Durante el desarrollo del proyecto, se tuvo una sesión con colegas de SocialTIC que han estudiado mucho el tema de feminicidos, en las que se hicieron preguntas que pueden servir como punto de partida para análisis futuros:

  • ¿El lugar en donde ocurrió el feminicidio tiene impacto para que se vuelva viral?
  • ¿Tiene alguna implicación el activismo digital?
  • ¿Cómo se moviliza la información por estados?
  • ¿Un caso se hace viral dependiendo de quién lo publica, quien habla de ellos y luego quién lo retoma?

Adicional a estas durante esta sesión se comentó el hecho de que las conversaciones dentro de Facebook Groups se pudieron ver influenciados por la postura de algún mediador, sin embargo, no se cuenta con la información de si los grupos cuentan o no con mediadores.